<?php

declare(strict_types=1);

namespace SignKit\Engine;

use Contract\Exceptions\ValidationException;

class FullParameterAlgorithmEngine implements AlgorithmEngineInterface
{
    private string $secret;
    private array $debugInfo = [];

    /**
     * @param string $secret
     * @return bool
     * @throws ValidationException
     */
    public function setSecret(string $secret): bool
    {
        if (empty($secret)) {
            throw new ValidationException('秘钥不能为空');
        }
        $this->secret = $secret;
        return true;
    }

    /**
     * @param array $params
     * @return string
     * @throws ValidationException
     */
    public function generate(array $params): string
    {
        if (empty($params)) {
            throw new ValidationException('参数不能为空');
        }
        if (empty($this->secret)) {
            throw new ValidationException('还未设置秘钥');
        }
        $params = $this->parseParams($params);
        ksort($params);
        $params['secret'] = $this->secret;
        $this->setDebugInfo('params', $params);
        $paramString = $this->buildQueryString($params);
        $this->setDebugInfo('params_string', $paramString);
        return md5($paramString);
    }

    /**
     * @param array $params
     * @param string $prefix
     * @return array
     */
    public function parseParams(array $params, string $prefix = ''): array
    {
        $newParams = [];
        foreach ($params as $key => $value) {
            if ($this->isEmpty($value)) {
                continue;
            }
            $value = $this->formatValue($value);
            $currentPrefix = !empty($prefix) ? $prefix . '.' . $key : $key;
            if (is_array($value)) {
                $newParams = array_merge($newParams, $this->parseParams($value, $currentPrefix));
            } else {
                $newParams[$currentPrefix] = $value;
            }
        }
        return $newParams;
    }

    /**
     * 格式化
     * @param $value
     * @return array|int
     */
    protected function formatValue($value)
    {
        if (is_object($value)) {
            $value = (array)$value;
        }
        if (is_bool($value)) {
            $value = intval($value);
        }
        return $value;
    }

    /**
     * 是否为空
     * @param $value
     * @return bool
     */
    protected function isEmpty($value): bool
    {
        if (is_null($value)) {
            return true;
        }
        if (is_string($value) && empty($value)) {
            return true;
        }
        if (is_array($value) && empty($value)) {
            return true;
        }
        if (is_object($value) && empty($value)) {
            return true;
        }
        return false;
    }

    /**
     * User: Luw
     * Datetime: 2020/8/17 16:09
     * @param $params
     * @return string
     */
    protected function buildQueryString($params): string
    {
        $queryData = [];
        foreach ($params as $key => $value) {
            $queryData[] = sprintf('%s=%s', $key, $value);
        }
        return implode('&', $queryData);
    }

    /**
     * @return array
     */
    public function getDebugInfo(): array
    {
        return $this->debugInfo;
    }

    /**
     * @param $key
     * @param $info
     * @return bool
     */
    protected function setDebugInfo($key, $info): bool
    {
        $this->debugInfo[$key] = $info;
        return true;
    }
}